
;
;
;		S E C T I O N . M A C
;
;
; 09/04/85 modified for use with ZCPR2 and converted to Zilog
; mnemonics for assembly with Microsoft's M80 Assembler by Max Southall
;		Micro/Access, Box 136 Station J, Toronto
;		(416) 463 9360   2400/1200/300
;
; from SECTION.ASM, originally by Ron Fowler, Westland, Michigan  06/27/82
;
; This program is intended for RCPM systems where
; files are grouped into drive/user area by their
; classification.  This program implements a naming
; convention, whereby a caller can move into a
; section by typing its name, rather than the random
; searching formerly needed. If proper equates are set, and
; ZCPR2 is used, the program will not allow changing to 
; restricted drives or user areas. A resident or disk-based 
; command can be run after a section change if using the ZCPR2
; external command buffer.  If the section name buffer is implemented
; in the BIOS and custom ZCPR2, then the section name can be displayed
; as the prompt.
;
; Syntax is:  SECTION [<section-name>]
;
; If section-name is omitted, a short list of
; available sections is printed. The special
; form "SECTION ?" prints the detailed description
; of each section.
;
; You have to fill in the sections table
; (located near the end of this program) for your
; particular system.
;
;----< Examples of use: >-----
;
; A0>SECTION ZCPR	;changes drive/user to ZCPR area
; B4>SECTION MBASIC	;changes drive/user to mbasic area
; A6>SECTION		;prints short list of sections
; A9>SECTION ?		;prints the detailed list
;
false	EQU	0	
true	EQU	not false
;
; the following equates may be
; customized to your preference
;
zcmd	EQU	TRUE	;ZCPR2/3 multiple command buffer used?
			;If using ZCPR2 command buffer, run command at
			;CMD after new section is selected.  
check	EQU	TRUE	;check maximum drive and user permitted
cmdbuf	EQU	0fe80h	;address of zcpr2/3 multiple command buffer
;
prompt	EQU	TRUE	;make prompt section name (must implement sname
			;in modified ZCPR2/3 and initialize in BIOS)
sname	EQU	0f2b0h+49+49  ;address of section name prompt buffer
;
maxuser	EQU	03fh	;address of maximum user # byte
maxdriv	EQU	03dh	;address of maximum drive # byte
;
descol	EQU	15	;column # where description begins
			;(in detailed list) (should be greater
			;than longest section name) (but small
			;enuf so display is not too long)
perlin	EQU	4	;names printed per line in short list
tabpos	EQU	12	;tab stops (set mod tabpos)
			;should be at least one greater than
			;longest section name.
;
lines	EQU	18	;line # to pause at so screen doesn't overflow
;
; ZCPR conventions
;
cpbase	EQU	0	
ccpdrv	EQU	cpbase+4	;ccp user/drive storage loc
bdos	EQU	cpbase+5	;system entry point
dfcb	EQU	cpbase+5CH	;default file control block
dbuf	EQU	cpbase+80H	;default buffer
tpa	EQU	cpbase+100H	;base of transient program area
coninf	EQU	1	;system call, get console char
conotf	EQU	2	;system call, console output
printf	EQU	9	;system call, print cons string
cstsf	EQU	11	;system call, get console status

;
; character definitions
;
cr	EQU	13	;carriage-return code
lf	EQU	10	;linefeed code
;
; code begins....
;
	.Z80	;Accept Z80 instruction format
;
	ORG	tpa
;
;
pbase:
	LD	HL,0	;save system stack
	ADD	HL,SP
	LD	(spsave),HL
	LD	SP,stack	;load local stack
;
	LD	A,(ccpdrv)	;get current drive #
	LD	(lastdrv),A	;save
	PUSH	AF	;save it
;
gosect:
	CALL	sect	;perform the section function
;
back:
	LD	HL,(spsave)	;restore stack for proper return
	LD	SP,HL

	LD	A,(lastdrv)	;check to see if section changed
	LD	B,A
	LD	A,(ccpdrv)
	CP	B
	RET	Z	;no section change, exit but don't warmboot
	
	 if	prompt
	ld	(sname),a	;put drv/usr in sname buffer
	ld	hl,(savecmd)
	ld	de,sname+1
putsname:
	ld	a,(hl)
	ld	(de),a
	cp	0
	jr	z,swarm
	inc	hl
	inc	de
	jr	putsname
	 
	 endif

swarm:
	JP	cpbase	;CCP will change section at warmboot
;
;
; scan cmd line...if an arg exists, attempt to
; match it in the table.  If no arg, dump a list
; of available sections.
;
sect:
	LD	A,(dfcb+1)	;is there a cmd-line arg?
	CP	' '
	JP	Z,prnqk	;then go print sections out
	CP	'?'	;wants detailed list?
	JP	Z,prntbl	;then go do it
;
;	SCAN FOR SECTION & CHANGE IF LEGAL
;
	LD	HL,dbuf	;something there, scan to it
;
scanbk:
	INC	HL	;  ignoring blanks
	LD	A,(HL)
	CP	' '
	JP	Z,scanbk
scant:
	LD	(savecmd),HL
	LD	DE,table	;point de to the section table
	CALL	loop
scant1:
	LD	HL,(savecmd)
	LD	DE,table1
	CALL	loop
scant2:	
	LD	HL,(savecmd)	
	LD	DE,table2
	CALL	loop	
scant3:
	LD	HL,(savecmd)	
	LD	de,table3
	CALL	loop
;
	LD	DE,matmsg	;print out no-match message
	LD	C,printf
	CALL	bdos
;
	CALL	prnqk	;go give short list	
	RET
;
loop:
	PUSH	HL	;save cmd line arg pointer
eloop:
	LD	A,(DE)	;test entry against table
	CP	1	;end of entry marker?
	JP	NZ,noend	;jump if not
	LD	A,(HL)	;yes, did user cmd terminate also?
	OR	A
	JP	Z,match	;then declare a match

	JP	nomat	;else declare a mismatch

noend:
	CP	(HL)
	JP	NZ,nomat	;skip if no match
	INC	HL	;continue with comparison
	INC	DE
	JP	eloop
;
; here when an entry didn't match
;
nomat::	LD	A,(DE)
	OR	A	;entry terminator?
	INC	DE
	JP	NZ,nomat	;scan through it
	POP	HL	;restore cmd line arg pntr
	INC	DE	;end of entry, skip over user #
	INC	DE	;and drive
	LD	A,(DE)	;end of table?
	OR	A	;(terminated by 0)
	JP	NZ,loop	;go scan another if not
;
; here when no match can be found
;
	ret
;
; here when a match is found
;
match:
	EX	DE,HL	;hl==> user #
scmat:
	INC	HL	;scan past description
	LD	A,(HL)	;looking for terminating null
	OR	A
	JP	NZ,scmat

	INC	HL	;skip over terminator
	LD	A,(HL)	;fetch user #
	SUB	'0'	;subtract ascii bias
	CP	10	;is it > 15?
	JP	C,scmat2	;no, so continue on
	SUB	7	;remove the rest 
scmat2::
	LD	(user),A
	LD	E,A
	INC	HL	;point hl to drive #
	LD	A,(HL)	;fetch drive
	SUB	'A'	;subtract ascii bias
	LD	(drive),A
	LD	D,A	;save drive #
	LD	A,E	;fetch user number
	RLC	A	;rotate to high nybble
	RLC	A
	RLC	A
	RLC	A
	OR	D	;"or" in the drive

	POP	DE	;clear garbage from stack

	 if	check	;if checking maxdrive & user

	LD	(newdrive),A	;save while we check for limits
chkd:
	LD	A,(drive)	;check for maximum drive first
	LD	HL,maxdriv
	INC	(HL)
	CP	(HL)
	JR	NC,restrict	;illegal request - don't change section
chku:
	LD	A,(user)	;check for maximum user area
	LD	HL,maxuser
	INC	(HL)
	CP	(HL)
	JR	C,okset		;ok - change section
;
restrict:
	LD	DE,rstrmsg	;print illegal request message
	LD	C,printf
	CALL	bdos
	jr	cmdret			;return without changing section
;
okset:
	LD	A,(newdrive)	;restore request

	 endif		;if checking maxuser & maxdrive	


;	-- Change user/drive at 04H for the ccp

	LD	(ccpdrv),A	;save drive/user for ccp use
;
	 if	zcmd		;if running a command after section change
;
	LD	B,A
	LD	A,(lastdrv)
	CP	B
	JR	Z,cmdret
;
; Place command to run after section change in ZCPR2/3 multiple command buffer
;
	LD	HL,cmd		;address of command to run
	LD	DE,cmdbuf+4	;place to put command
	LD	(cmdbuf),DE	;store address of command
transcmd:
	LD	A,(HL)		;get command letter
	CP	'$'		;end of command delimiter?
	JR	Z,cmdret		;if so, return		
	LD	(DE),A		;put cmd letter in cmd buffer
	INC	HL		;bump 'em both
	INC	DE
	JR	transcmd	;do again until finished

	 endif
cmdret:
	POP	HL		;dummy clear stack for proper return
	RET			;return to caller
;
; 	PRINT QUICK LIST
;
prnqk:
	LD	DE,signon
	LD	C,printf
	CALL	bdos

prnqk1:
	LD	DE,tblmsg
	LD	C,printf
	CALL	bdos
	LD	HL,table
	call	qloop
	LD	HL,table1
	call	qloop
	LD	HL,table2
	CALL	qloop
	LD	HL,table3
	CALL	qloop
;
	LD	DE,matms2	;print ending message
	LD	C,printf
	CALL	bdos
	CALL	crlf
;
	RET
;
qloop::	LD	B,perlin	;get names-per-line counter
qloop2::LD	A,(HL)	;end of table?
	OR	A
	JP	Z,qkend	;then go print end msg
	CALL	prathl	;else print the name
qscan::	LD	A,(HL)	;scan to description terminator
	INC	HL	;(this effectively ignores
	OR	A	; the description)
	JP	NZ,qscan
	INC	HL	;skip over user #
	INC	HL	;and drive #
	DEC	B	;count down line entry counter
	JP	NZ,qtab	;go tab if line not full
	CALL	crlf	;else turn up new line
	JP	qloop	;and continue
;
; tab between entry names
;
qtab::	LD	A,' '	;seperate names with tabs
	CALL	type
	LD	A,(column)	;get column #
qsub::	SUB	tabpos	;test tab position
	JP	Z,qloop2	;continue if at a tab position
	JP	NC,qsub	;convert mod tabpos
	JP	qtab	;keep tabbing
;
qkend:
	CALL	crlf
	RET	
;
; here to print out a list of available section numbers
;
prntbl::
	LD	DE,signon
	LD	C,printf
	CALL	bdos

	LD	A,(dfcb+2)
	CP	'Z'
	jr	Z,prnt1
	CP	'P'		
	jr	Z,prnt2		
	CP	'M'
	jr	Z,prnt3

prtall:
	LD	DE,tblmsg
	LD	C,printf
	CALL	bdos
	LD	HL,table
	CALL	prloop1
	CALL	prnt1
	call	prnt2
	call	prnt3
	ret
;	
prnt1:
	LD	DE,tbl1msg
	LD	C,printf
	CALL	bdos
	LD	HL,table1
	CALL	PRLOOP1
	RET
prnt2:
	LD	DE,tbl2msg
	LD	C,printf
	CALL	bdos
	LD	HL,table2
	CALL	prloop1
	RET

prnt3:
	LD	DE,tbl3msg
	LD	C,printf
	CALL	bdos
	LD	HL,table3
	CALL	prloop1
	ret
prloop1:
	CALL	crlf
prloop:
	LD	A,(HL)	;end-of-table?
	OR	A
	RET	Z	;then all done
	CALL	prathl	;print the name
tab::	LD	A,'.'	;tab over with leader
	CALL	type
	LD	A,(column)	;get column
	CP	descol	;at description column yet?
	JP	C,tab	;then keep tabbing
	CALL	prathl	;print description
	INC	HL	;skip over user #
	INC	HL	;and drive number
	CALL	crlf	;turn up new line
;
; pause for user input before continuing if screen end reached	
;
	PUSH	HL		;save HL
	LD	HL,lincount	;current linecount
	LD	A,lines		;# of lines permitted before pause
	CP	(HL)		;max # of lines yet?
	JR	NZ,cprat	;not yet - continue listing
;
prtpause:
	LD	DE,pausemsg	;print pause message
	LD	C,printf
	CALL	bdos
;
getinp:
	LD	C,coninf	;get user input
	CALL	bdos			
	AND	5FH
	CP	'N'		;Exit?
	JR	Z,cprat2
	CP 	'C'-40h
	JR	Z,cprat2
	ld	c,conotf
	ld	e,cr
	CALL	bdos
	XOR	A		;CR - zero lincount
	LD	(lincount),A
	JR	cprat1
cprat:	
	INC	(HL)		;bump line counter
cprat1:
	POP	HL		;restore HL
;
	JP	prloop	;and continue printing list

cprat2:
	POP	HL
	POP	HL
	POP	HL
	RET
;
; print message @hl until null or 01 binary
;
prathl::LD	A,(HL)	;fetch char
	INC	HL	;point past it
	OR	A	;null?
	RET	Z	;then done
	CP	1	;1 also terminates
	RET	Z
	CALL	type	;nope, print it
	CALL	break	;check for console abort
	JP	prathl
;
; test for request from console to stop (^C)
;
break::	PUSH	HL	;save 'em all
	PUSH	DE
	PUSH	BC
	LD	C,cstsf	;get console sts request
	CALL	bdos
	OR	A	;anything waiting?
	JP	Z,brback	;exit if not
	LD	C,coninf	;there, is, get it
	CALL	bdos
	CP	'S'-64	;got pause request?
	LD	C,coninf
	CALL	Z,bdos	;then wait for another character
	CP	'C'-64	;got abort request?
	JP	Z,quit	;then go abort
brback::POP	BC	;else restore and return
	POP	DE
	POP	HL
	RET	
;
; request from console to abort
;
quit::	LD	DE,qmesg	;tell of quit
	LD	C,printf
	CALL	bdos
	LD	HL,(spsave)	;get stack pointer
	LD	SP,HL
	RET	
;
qmesg::	DB	cr,lf,'==> Aborted',cr,lf,'$'
;
; turn up a new line on display
;
crlf::	LD	A,cr	;print a return
	CALL	type
	LD	A,lf	;get lf, fall into type
;
; Routine to print char in A on console,
; while maintaining column number. 
;
type::	PUSH	HL	;save everybody
	PUSH	DE
	PUSH	BC
	LD	E,A	;align char for printing
	PUSH	AF	;save char
	LD	C,conotf
	CALL	bdos	;print it
	POP	AF	;restore char
	LD	HL,column	;bump column counter
	CP	lf	;linefeed doesn't chang column
	JP	Z,nochg
	INC	(HL)
	CP	cr	;carriage-return zeroes it
	JP	NZ,nochg	;skip if not cr
	LD	(HL),0	;is, zero column
nochg::	POP	BC	;restore & return
	POP	DE
	POP	HL
	RET	
;
; dump heading message
;
signon:	DB	cr,lf,'Micro/Access SECTION  9/4/85',cr,lf,'$' 
;
tblmsg: DB	cr,lf,'Currently available sections:',cr,lf,'$'
;
tbl1msg: DB	cr,lf,'Current ZCPR-CP/M sections:',cr,lf,'$'
;
tbl2msg: DB	cr,lf,'Current PC/XT/AT sections:',cr,lf,'$'
;
tbl3msg: DB	cr,lf,'Current MAC sections:',cr,lf,'$'
;
rstrmsg: DB	cr,lf,'==> Restricted',cr,lf,'$'
;
pausemsg: DB	'>>> MORE? <Y/N> - $'	
;
; message printed when match failed
;
matmsg::DB	cr,lf,'==> ??? Section'
	DB	cr,lf,'$'
matms2:
	DB	cr,lf,lf,'Type "SECTION <section-name>" to log into a section.'
	DB	cr,lf
	DB	'"SECTION ?" - detailed list of ALL sections',cr,lf
	DB	'?P - PC/XT/AT sections',cr,lf
	DB	'?Z - 8080/Z80/HD64180 sections',cr,lf
	DB	'?M - MAC sections',cr,lf
	DB	'"SECTION" alone prints available section names' 
	DB	cr,lf,'$'
;
;	Patch command to execute here
;
cmd: DB	'DIR',0,'$'		;command to execute after changing sections
				;'$' is to delimit transfer to cmdbuffer,
				;cmd itself must always end with 0 for ZCPR2/3.
;
; variables
;
spsave: DW	0	;stack-pointer save
savecmd: DW 	0	;pointer to section command in buffer 
column: DB	0	;current column #
lincount: DB	0	;current line printed
lastdrv: DS	1	;drive/user before execution
newdrive: DS	1	;requested drive/user
drive:	DS	1	;requested drive
user:	DS	1	;requested user	
	DS	40	;the stack
;
stack	EQU	$	;define it
;
;
;
;
; SECTIONS TABLE (located at end for easy patching with ZSID)
;
; This is the table that defines the sections.	Entry format is:
;
;	<name>,sep,<description>,null,user,drive
;
; where <name>	       is the section name
;	sep	       is a binary 1 used to terminate the match test
;	<description>  is a one-line-or-less comment printed when
;		       the list is dumped.  Match testing terminates
;		       before this field.
;	null	       is a binary 0 used to terminate the description
;	user	       is the user number (0-15) of the section (ascii)
;	drive	       is the drive (A-P) number of the section (ascii)
;
; the table ends with a <name> of zero (binary).
;
; Note: be sure to make section names ALL-CAPS, because the
;	CCP converts command-line arguments to capitals. The
;	description may be in lower case, since it has nothing
;	to do with the matching process.
; Also: although the drive and user # is in ascii (for convenience
;	in setting up the table), be sure to use caps for the
;	drive designation.  No error checking is done on the values.
;
table:
	DB	'UPLOADS',1,'Recent User Uploads',0,'0B'
	DB	'DOCS',1,'Documentation & Text',0,'0C'
	DB	'TRACE',1,'TRACE Computer Club Related Files',0,'DE'
	DB	0	;<<== end of table 0
table1:
	DB	'APPLE-80',1,'Apple CP/M-ZCPR Programs',0,'5C'
	DB	'ASM-80',1,'Z80/HD64180 Assembly Language Area',0,'1B'
	DB	'BBS-80',1,'Remote Communication for ZCPR-CP/M',0,'6B'
	DB	'C-80',1,'C Language Area for ZCPR-CP/M',0,'3C'
	DB	'CATS-80',1,'SIG/M, CP/MUG Catalogs',0,'BB'
	DB	'COMM-80',1,'Modem programs for ZCPR-CP/M',0,'4B'
	DB	'CPM-86',1,'CP/M-86 Area',0,'2E'
	DB	'DBASE',1,'DBASEII programs',0,'AC'
	DB	'EMX',1,'Simon Ewins'' remote message/software system',0,'4C'
	DB	'S100',1,'Source for Multiflex, other S100',0,'8C'
	DB	'SYS-80',1,'ZCPR-CP/M System Files',0,'2B'
	DB	'UTIL-80',1,'ZCPR-CP/M Utilities',0,'3B'
	DB	'VIDTEK',1,'Source for SBC-80, JLS BB',0,'6C'
	DB	'WORD-80',1,'Word-processing related files',0,'9C'
	DB	'XEROX',1,'Source for XEROX 820-I',0,'7C'
	DB	'ZCPR2',1,'ZCPR2 processor for CP/M-80',0,'BC'
	DB	'ZCPR3',1,'ZCPR3 processor for CP/M-80',0,'CC'
	DB	0	;<<== end of table1
table2:
	DB	'PC-COMM',1,'Modem programs for PC/XT/AT',0,'1D'
	DB	'PC-GAME',1,'Games for PC/XT/AT',0,'4D'
	DB	'PC-KERMIT',1,'Columbia U''s Communications Program',0,'3E'
	DB	'PC-MASM',1,'8086/286 Assembly Language Source',0,'7D'
	DB	'PC-PROG',1,'General Program Area',0,'8D'
	DB	'PC-RBBS',1,'Remote system software',0,'6D'
	DB	'PC-TURBO',1,'Turbo Pascal Files',0,'1E'
	DB	'PC-UTIL1',1,'Utilities for IBM PC/XT/AT',0,'0D'
	DB	'PC-UTIL2',1,'More PC/XT/AT Utilities',0,'2D'
	DB	'PC-WORD',1,'Word processing related files',0,'5D'
	DB	0	;<<== end of table2
table3:
	DB	'MAC',1,'Apple MACINTOSH Area',0,'0F'	
	DB	0	;<<== end of table3
;
; -----< end of SECTIONS table>-----
;
	END	pbase	;that's all.
